package com.cfc.mongodb.utils;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.cfc.mongodb.entity.MongoDbBaseModel;
import com.cfc.mongodb.entity.PageParam;
import com.cfc.mongodb.vo.PageResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.List;

/**
 * Description: mongodb操作器
 *【公共字段处理】
 *【查询分页封装】
 * @author zqs
 */
@Service("mongoHelper")
public class MongoHelper {


    @Autowired
    private MongoTemplate mongoTemplate;

    /**
     * 新增/编辑-基础方法（BaseModel）
     *
     * @param model
     * @param mongoRepository
     * @param <T>
     * @return
     */
    public <T extends MongoDbBaseModel> T save(T model, MongoRepository<T, String> mongoRepository) {
        return mongoRepository.save(model);
    }


    /**
     * 新增-批量（BaseModel）
     *
     * @param <T>
     * @param modelList
     * @param mongoRepository
     * @return
     */
    public <T extends MongoDbBaseModel> Collection<T> insertBatch(List<T> modelList, MongoRepository<T, String> mongoRepository) {
        return mongoRepository.insert(modelList);
    }

    /**
     * 新增-批量（BaseModel）
     *
     * @param modelList
     * @param <T>
     * @return
     */
    public <T extends MongoDbBaseModel> Collection<T> saveBatch(List<T> modelList, MongoRepository<T, String> mongoRepository) {
        return mongoRepository.saveAll(modelList);
    }

    /**
     * 根据id删除
     *
     * @param id    对象
     * @param clazz 类
     */
    public void deleteById(String id, Class<?> clazz) {
        if (StrUtil.isEmpty(id)) {
            return;
        }
        Object object = ReflectUtil.newInstance(clazz);
        ReflectUtil.setFieldValue(object, "id", id);
        mongoTemplate.remove(object);
    }

    /**
     * 根据条件删除
     *
     * @param query 查询
     * @param clazz 类
     */
    public void deleteByQuery(Query query, Class<?> clazz) {
        mongoTemplate.remove(query, clazz);
    }

    /**
     * 根据条件删除
     *
     * @param criteria 查询
     * @param clazz    类
     */
    public void deleteByQuery(Criteria criteria, Class<?> clazz) {
        deleteByQuery(new Query(criteria), clazz);
    }


    /**
     * 按查询条件获取Page
     *
     * @param query 查询
     * @param page  分页
     * @param clazz 类
     * @return Page 分页
     */
    public PageResult findPage(Query query, PageParam page, Class<?> clazz) {
        // 查询出一共的条数
        Long count = mongoTemplate.count(query, clazz);
        // 查询page
        query.skip((page.getCurrent() - 1) * page.getLimit());// 从那条记录开始
        query.limit(page.getLimit());// 取多少条记录

        List<?> list = mongoTemplate.find(query, clazz);
        PageResult pageResult = new PageResult(page, count, list);
        return pageResult;
    }

    /**
     * 按查询条件获取Page
     *
     * @param criteria 查询
     * @param page     分页
     * @param clazz    类
     * @return Page 分页
     */
    public PageResult findPage(Criteria criteria, PageParam page, Class<?> clazz) {
        return findPage(new Query(criteria), page, clazz);
    }

    /**
     * 按查询条件获取Page
     *
     * @param criteria 查询
     * @param sort     排序
     * @param clazz    类
     * @return Page 分页
     */
    public PageResult findPage(Criteria criteria, Sort sort, PageParam page, Class<?> clazz) {
        return findPage(new Query(criteria).with(sort), page, clazz);
    }

    /**
     * 获取Page
     *
     * @param page  分页
     * @param clazz 类
     * @return Page 分页
     */
    public PageResult findPage(PageParam page, Class<?> clazz) {
        return findPage(new Query(), page, clazz);
    }

    /**
     * 根据id查找
     *
     * @param id    id
     * @param clazz 类
     * @return T 对象
     */
    public <T> T findById(String id, Class<T> clazz) {

        if (StrUtil.isEmpty(id)) {
            return null;
        }
        return (T) mongoTemplate.findById(id, clazz);
    }

    /**
     * 根据id集合查找
     *
     * @param ids
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> List<T> findListByIds(Collection<String> ids, Class<T> clazz) {
        return findListByQuery(new Query(Criteria.where("id").in(ids)), clazz);
    }

    /**
     * 根据条件查找单个
     *
     * @param query 查询
     * @param clazz 类
     * @return T 对象
     */
    public <T> T findOneByQuery(Query query, Class<T> clazz) {
        query.limit(1);
        return mongoTemplate.findOne(query, clazz);
    }

    /**
     * 根据条件查找单个
     *
     * @param <T>      类型
     * @param criteria
     * @param clazz    类
     * @return T 对象
     */
    public <T> T findOneByQuery(Criteria criteria, Class<T> clazz) {
        return findOneByQuery(new Query(criteria), clazz);
    }

    /**
     * 根据条件查找List
     *
     * @param <T>   类型
     * @param query 查询
     * @param clazz 类
     * @return List 列表
     */
    public <T> List<T> findListByQuery(Query query, Class<T> clazz) {
        return mongoTemplate.find(query, clazz);
    }

    /**
     * 根据条件查找List
     *
     * @param <T>      类型
     * @param criteria 查询
     * @param clazz    类
     * @return List 列表
     */
    public <T> List<T> findListByQuery(Criteria criteria, Class<T> clazz) {
        return (List<T>) findListByQuery(new Query(criteria), clazz);
    }

    /**
     * 根据条件查找List
     *
     * @param <T>      类型
     * @param criteria 查询
     * @param sort     排序
     * @param clazz    类
     * @return List 列表
     */
    public <T> List<T> findListByQuery(Criteria criteria, Sort sort, Class<T> clazz) {
        return (List<T>) findListByQuery(new Query(criteria).with(sort), clazz);
    }

    /**
     * 查询全部
     *
     * @param <T>   类型
     * @param clazz 类
     * @return List 列表
     */
    public <T> List<T> findAll(Class<T> clazz) {
        return findListByQuery(new Query(), clazz);
    }

    /**
     * 查询全部
     *
     * @param <T>   类型
     * @param clazz 类
     * @return List 列表
     */
    public <T> List<T> findAll(Sort sort, Class<T> clazz) {
        return findListByQuery(new Criteria(), sort, clazz);
    }

    /**
     * 根据条件判断是否存在
     * @param query
     * @param clazz
     * @return
     */
    public Boolean findExists(Query query, Class<?> clazz) {
        return mongoTemplate.exists(query, clazz);
    }

    /**
     * 根据条件判聚合查询
     * @param aggregation
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> AggregationResults<T> findByAggregate(TypedAggregation<?> aggregation, Class<T> clazz) {
        return mongoTemplate.aggregate(aggregation, clazz);
    }

    /**
     *去重查询
     * @param <T>
     * @param query
     * @param field
     * @param collectionName
     * @param clazz
     * @param resultClass
     * @return
     */
    public <T> List<T> findDistinct(Query query, String field, String collectionName, Class<?> clazz, Class<T> resultClass) {
        return mongoTemplate.findDistinct(query,field,collectionName,clazz,resultClass);
    }
}
